package pkg.andru.collect;

/**
 * non blocking queue: <br>
 * 1.FIFO; </br> 2.all method is thread safe;</br>3.when size bigger than
 * queue's size, will pop queue' head item
 * 
 * @author idiottiger
 * @version 1.0
 * @param <T>
 */
public class NonBlockingQueue<T> {

    /**
     * default queue size.
     */
    public static final int DEFAULT_SIZE = 40;

    /**
     * using array to implements
     */
    private Object[] arrays;

    private int head, tail, size;

    /**
     * default constructur, using default queue size to init.
     */
    public NonBlockingQueue() {
        this(DEFAULT_SIZE);
    }

    /**
     * using your self's size to init the queue's length.
     */
    public NonBlockingQueue(int size) {
        if (size <= 0) {
            throw new IllegalArgumentException();
        }
        arrays = new Object[size];
        this.size = size;
        head = tail = 0;
    }

    /**
     * push method
     * 
     * @param t
     */
    public synchronized void push(T t) {
        if (isFull()) {
            pop();
        }
        arrays[tail] = t;
        tail = (tail + 1) % size;
    }

    /**
     * pop method
     * 
     * @return t
     */
    @SuppressWarnings("unchecked")
    public synchronized T pop() {
        if (isEmpty()) {
            return null;
        } else {
            T t = (T) arrays[head];
            arrays[head] = null;
            head = (head + 1) % size;
            return t;
        }
    }

    /**
     * check the queue is empty or not
     * 
     * @return true or false
     */
    public synchronized boolean isEmpty() {
        return tail == head && arrays[head] == null;
    }

    public synchronized boolean isFull() {
        return tail == head && arrays[tail] != null;
    }

    /**
     * clear all element in the queue and reset.
     */
    public synchronized void clear() {
        for (Object obj : arrays) {
            if (obj != null) {
                obj = null;
            }
        }
        head = tail = 0;
    }

    public synchronized boolean contain(T t) {
        for (Object obj : arrays) {
            if (t.equals(obj)) {
                return true;
            }
        }
        return false;
    }

    @SuppressWarnings("unchecked")
    public synchronized T getItem(int i) {
        if (i >= 0 && i < size) {
            return (T) arrays[i];
        }
        return null;
    }

    @Override
    public String toString() {
        return super.toString();
    }

}
